//============================================================================================
/**
 * @file	opening_demo.c
 * @brief	オープニングデモ
 * @author	Nozomu Saito
 * @date	2006.05.31
 */
//============================================================================================
#include "common.h"
#include "system/palanm.h"
#include "system/lib_pack.h"
#include "system/snd_tool.h"
#include "system/brightness.h"
#include "system/arc_tool.h"
#include "system/arc_util.h"
#include "system/wipe.h"
#include "system/main.h"

#include "field/field.h"

#include "opening_demo_local.h"
#include "opd_scene1.h"
#include "opd_scene2.h"
#include "opd_scene3.h"
#include "opd_scene4.h"
#include "opd_scene5.h"

#include "op_demo.naix"

#ifdef PM_DEBUG
#define COPYRIGHT_SKIP				//<< 有効にすると著作権情報をスキップできます
#define OPENING_DEMO_SKIP_GS		//<< 有効にするとオープニングデモがGFロゴで終わります
//#define CPRIGHT_OPENING_BGM_ON	//<< 有効にするとオープニングデモの曲がなります。

#endif

#define WIPE_RAD	(0x8000)
#define SCENE_MAX	(5)

///	タイトル全体制御用ワーク構造体
typedef struct OPENING_DEMO_WORK_tag
{
	int	HeapID;
	int FrameCounter;
	BOOL SkipFlg;

	GF_BGL_INI*		bgl;	// BGマネージャ
///	GF_G3DMAN*		g3Dman;	// 3Dマネージャ

	CLACT_SET_PTR 			ClactSet;	// セルアクターセット
	CLACT_U_EASYRENDER_DATA	RendData;	// 簡易レンダーデータ
	CLACT_U_RES_MANAGER_PTR	ResMan[RESOURCE_NUM];				// リソースマネージャ

	u32 RandSeed;

	SCENE1_WORK		SceneWork1;
	SCENE2_WORK		SceneWork2;
	SCENE3_WORK		SceneWork3;
	SCENE4_WORK		SceneWork4;
	SCENE5_WORK		SceneWork5;

	DISP_EFF_WORK	Dew;
	u8 SkipOK;
	u8 SceneSeq;
	u8 SceneCounter;
	u8 SceneNo;

}OPENING_DEMO_WORK;

extern const PROC_DATA TitleProcData;
extern void		Main_SetNextProc(FSOverlayID ov_id, const PROC_DATA * proc_data);
FS_EXTERN_OVERLAY( title );


static PROC_RESULT OpDemo_Init(PROC * proc, int * seq);
static PROC_RESULT OpDemo_Main(PROC * proc, int * seq);
static PROC_RESULT OpDemo_Exit(PROC * proc, int * seq);
static void InitCellActor(OPD_WK_PTR wk);
static void EndCellActor(OPD_WK_PTR wk);


static void TCB_BlendIn( TCB_PTR tcb, void* work );

static void TCB_Scroll( TCB_PTR tcb, void* work );
static void TCB_ScrollNorm( TCB_PTR tcb, void* work );

static u8 GetFrmIdx(const int inBgFrame);

static void TCB_Wnd( TCB_PTR tcb, void* work );
static void SetWindouw(	const int inInside, const inOutside,
						const u8 inInEff, const u8 inOutEff, const BOOL inIsMain);
static void SetWinRect(const int inSX, const int inSY, const int inEX, const int inEY, const BOOL inIsMain );


static void TCB_Wipe( TCB_PTR tcb, void* work );
static void WipeHBlank( void* p_work );

static void *GetSceneWorkPtr(OPD_WK_PTR ptr);

//GS
static void SetVramBank(void);
static void DrawActor(OPD_WK_PTR wk);

typedef BOOL (*SCENE_FUNC)(OPD_WK_PTR wk, void *work);

//シーンテーブル
SCENE_FUNC SceneTbl[5] = {
	OPD_Scene1,
	OPD_Scene2,
	OPD_Scene3,
	OPD_Scene4,
	OPD_Scene5,
};

#ifdef PM_DEBUG
static u32 debug_memory_size = 0;
#endif

//=================================================================================================
//
// ＰＲＯＣ定義テーブル
//
//=================================================================================================
const PROC_DATA OpDemoProcData = {
	OpDemo_Init,
	OpDemo_Main,
	OpDemo_Exit,
	NO_OVERLAY_ID
};

//--------------------------------------------------------------------------------------------
/**
 * プロック　初期化関数
 *
 * @param	proc	プロックポインタ
 * @param	seq		シーケンス
 *
 * @return	PROC_RESULT		PROC_RES_FINISHを返す
 */
//-------------------------------------------------------------------------------------------
static PROC_RESULT OpDemo_Init(PROC * proc, int * seq)
{
	OPD_WK_PTR wk;
	int	heapID;

#ifdef PM_DEBUG
	debug_memory_size = sys_GetHeapFreeSize( HEAPID_BASE_APP );
	OS_Printf("HEAPID_BASE_APP rest = %x\n",debug_memory_size);
#endif

	heapID = HEAPID_OP_DEMO;

	BrightnessChgInit();

	//マスター輝度をあげておく
	WIPE_SetBrightness( WIPE_DISP_MAIN,WIPE_FADE_BLACK );
	WIPE_SetBrightness( WIPE_DISP_SUB,WIPE_FADE_BLACK );

	sys_VBlankFuncChange( NULL, NULL );	// VBlankセット
	sys_HBlankIntrSet( NULL,NULL );		// HBlankセット

	GF_Disp_GX_VisibleControlInit();
	GF_Disp_GXS_VisibleControlInit();

	sys_KeyRepeatSpeedSet(4,8);
	sys_CreateHeap( HEAPID_BASE_APP, heapID, 0x68000 );

	wk = PROC_AllocWork(proc,sizeof(OPENING_DEMO_WORK),heapID);
	memset(wk,0,sizeof(OPENING_DEMO_WORK));

	wk->HeapID = heapID;

	wk->SkipFlg = FALSE;

#ifdef COPYRIGHT_SKIP
	wk->SkipOK = 1;
#else
	//始めはスキップ不可
	wk->SkipOK = 0;
#endif
	//３Ｄ描画スイッチ(下画面がメイン)
	sys.disp3DSW = DISP_3D_TO_SUB;
	GF_Disp_DispSelect();

	//乱数の種退避
	wk->RandSeed = gf_get_seed();

	//乱数初期化
	gf_srand(0);

	//BGライブラリ用メモリ確保
	wk->bgl = GF_BGL_BglIniAlloc(wk->HeapID);

	SetVramBank();
	InitCellActor(wk);

	return	PROC_RES_FINISH;

}

//--------------------------------------------------------------------------------------------
/**
 * プロック　メイン関数
 *
 * @param	proc	プロックポインタ
 * @param	seq		シーケンス
 *
 * @return	PROC_RESULT		メイン処理終了でPROC_RES_FINISHを返す
 */
//-------------------------------------------------------------------------------------------
static PROC_RESULT OpDemo_Main(PROC * proc, int * seq)
{
	OPD_WK_PTR wk = PROC_GetWork( proc );
#if 0
#ifdef PM_DEBUG
	if (/*sys.trg & PAD_BUTTON_X*/1){
		OS_Printf("frame:%d\n",wk->FrameCounter);
	}
#endif
#endif
	if ( (wk->SkipOK)&&( (sys.trg & PAD_BUTTON_A)||(sys.trg & PAD_BUTTON_START)|| sys.tp_trg ) )
	{
		wk->SkipFlg = TRUE;
		sys.DS_Boot_Flag = FALSE;	//ブートフラグセット
		WIPE_SetBrightness( WIPE_DISP_MAIN,WIPE_FADE_WHITE );
		WIPE_SetBrightness( WIPE_DISP_SUB,WIPE_FADE_WHITE );
	}

	switch(*seq){
	case 0:
		wk->SceneWork1.SkipOKPtr = &wk->SkipOK;
		Snd_DataSetByScene( SND_SCENE_OPENING, SEQ_GS_TITLE, 1 );
		(*seq)++;
		break;
	case 1:
		{
			void *sc_wk;
			sc_wk = GetSceneWorkPtr(wk);
			if ( SceneTbl[wk->SceneNo](wk, sc_wk) ){
				wk->SceneNo++;
				wk->SceneSeq = 0;
				wk->SceneCounter = 0;
				if (wk->SceneNo >= SCENE_MAX){
					(*seq)++;
				}
			}else{
				wk->SceneCounter++;
			}
		}
		break;
	case 2:
		if (/*wk->FrameCounter >= FM_END*/1){
			return	PROC_RES_FINISH;
		}
		break;
	default:
		GF_ASSERT(0);
		break;
	}

	if (wk->SkipFlg){
		OS_Printf("スキップにより、メインプロセス終了\n");
		return	PROC_RES_FINISH;
	}

	//アクター描画
	DrawActor(wk);

	wk->FrameCounter++;
	return	PROC_RES_CONTINUE;
}

//--------------------------------------------------------------------------------------------
/**
 * プロック　終了関数
 *
 * @param	proc	プロックポインタ
 * @param	seq		シーケンス
 *
 * @return	PROC_RESULT		PROC_RES_FINISHを返す
 */
//-------------------------------------------------------------------------------------------
static PROC_RESULT OpDemo_Exit(PROC * proc, int * seq)
{
	int i;
	OPD_WK_PTR wk = PROC_GetWork( proc );

	//両画面とも輝度を最大にしておく（パシリ防止）
	WIPE_SetBrightness( WIPE_DISP_MAIN, WIPE_FADE_WHITE );
	WIPE_SetBrightness( WIPE_DISP_SUB, WIPE_FADE_WHITE );

	EndCellActor(wk);

	sys_FreeMemoryEz( wk->bgl );

	//ブレンド
	if (wk->Dew.Blend.Tcb != NULL){
		TCB_Delete(wk->Dew.Blend.Tcb);
		wk->Dew.Blend.Tcb = NULL;
	}
	if (wk->Dew.BlendSub.Tcb != NULL){
		TCB_Delete(wk->Dew.BlendSub.Tcb);
		wk->Dew.BlendSub.Tcb = NULL;
	}
	//スクロール
	for(i=0;i<8;i++){
		if (wk->Dew.ScrlMng.Work[i].Tcb != NULL){
			TCB_Delete(wk->Dew.ScrlMng.Work[i].Tcb);
			wk->Dew.ScrlMng.Work[i].Tcb = NULL;
		}
	}
	//ウィンドウ
	for(i=0;i<2;i++){
		if ( wk->Dew.WndCnt.Work[i].Tcb != NULL ){
			TCB_Delete(wk->Dew.WndCnt.Work[i].Tcb);
			wk->Dew.WndCnt.Work[i].Tcb = NULL;
		}
	}
	//ワイプ
	if (wk->Dew.WipeWork.Tcb != NULL){
		TCB_Delete(wk->Dew.WipeWork.Tcb);
		wk->Dew.WipeWork.Tcb = NULL;
	}

	sys_VBlankFuncChange( NULL, NULL );	// VBlankセット
	sys_HBlankIntrSet( NULL,NULL );		// HBlankセット

	//ブレンド初期化
	G2_BlendNone();
	G2S_BlendNone();
	//ウィンドウ初期化
	GX_SetVisibleWnd(GX_WNDMASK_NONE);
	GXS_SetVisibleWnd(GX_WNDMASK_NONE);

	//ワイプの強制終了
	WIPE_SYS_ExeEnd();

	//乱数の種復帰
	gf_srand(wk->RandSeed);

	PROC_FreeWork( proc );				// ワーク開放
	sys_DeleteHeap( HEAPID_OP_DEMO );

#ifdef PM_DEBUG
	{
		int debug_mem_size = sys_GetHeapFreeSize( HEAPID_BASE_APP );
		OS_Printf("HEAPID_BASE_APP rest = %x\n",debug_mem_size);
		GF_ASSERT_MSG(debug_mem_size == debug_memory_size, "メモリリークの可能性があります。\n");
	}
#endif

	Main_SetNextProc( FS_OVERLAY_ID(title), &TitleProcData);
 	return	PROC_RES_FINISH;
}

#define ACT_MAX		(10)		//適当
#define PAL_MAX		(10)		//適当
#define DEMO_ACT_MAX	(20)		//適当
//アクター準備
#define CHAR_CONT_NUM				(ACT_MAX)
#define CHAR_VRAMTRANS_MAIN_SIZE	(0)
#define CHAR_VRAMTRANS_SUB_SIZE		(0)
#define PLTT_CONT_NUM				(PAL_MAX)


//--------------------------------------------------------------------------------------------
/**
 * 共通バンク設定
 *
 * @param	none
 *
 * @return	none
 */
//-------------------------------------------------------------------------------------------
static void SetVramBank(void)
{
	GF_BGL_DISPVRAM vramSetTable = {
		GX_VRAM_BG_128_B,				// メイン2DエンジンのBG
		GX_VRAM_BGEXTPLTT_NONE,			// メイン2DエンジンのBG拡張パレット
		GX_VRAM_SUB_BG_128_C,			// サブ2DエンジンのBG
		GX_VRAM_SUB_BGEXTPLTT_NONE,	// サブ2DエンジンのBG拡張パレット
		GX_VRAM_OBJ_32_FG,				// メイン2DエンジンのOBJ
		GX_VRAM_OBJEXTPLTT_NONE,		// メイン2DエンジンのOBJ拡張パレット
		GX_VRAM_SUB_OBJ_16_I,			// サブ2DエンジンのOBJ
		GX_VRAM_SUB_OBJEXTPLTT_NONE,	// サブ2DエンジンのOBJ拡張パレット
		GX_VRAM_TEX_0_A,				// テクスチャイメージスロット
		GX_VRAM_TEXPLTT_0123_E				// テクスチャパレットスロット
	};
	GF_Disp_SetBank( &vramSetTable );
}

//--------------------------------------------------------------------------------------------
/**
 * アクター描画
 *
 * @param	wk		ワーク
 *
 * @return	none
 */
//-------------------------------------------------------------------------------------------
static void DrawActor(OPD_WK_PTR wk)
{
	CLACT_Draw( wk->ClactSet );
}

//--------------------------------------------------------------------------------------------
/**
 * セルアクター初期化
 *
 * @param	wk		ワーク
 *
 * @return	none
 */
//-------------------------------------------------------------------------------------------
static void InitCellActor(OPD_WK_PTR wk)
{
	const int heapid = HEAPID_OP_DEMO;

	//マッピングモード設定
	GX_SetOBJVRamModeChar(GX_OBJVRAMMODE_CHAR_1D_32K);
	GXS_SetOBJVRamModeChar(GX_OBJVRAMMODE_CHAR_1D_32K);
	//キャラクター・パレットマネージャーの初期化
	{
		// キャラクタマネージャー初期化
		CHAR_MANAGER_MAKE cm = {
			CHAR_CONT_NUM,
			CHAR_VRAMTRANS_MAIN_SIZE,
			CHAR_VRAMTRANS_SUB_SIZE,
			heapid
		};
		InitCharManager(&cm);
		// パレットマネージャー初期化
		InitPlttManager(PLTT_CONT_NUM, heapid);

		// 読み込み開始位置を初期化
		CharLoadStartAll();
		PlttLoadStartAll();
	}

	// OAMマネージャーの初期化
	NNS_G2dInitOamManagerModule();

	// 共有OAMマネージャ作成
	// レンダラ用OAMマネージャ作成
	REND_OAMInit(
			0, 128,		// メイン画面OAM管理領域
			0, 32,		// メイン画面アフィン管理領域
			0, 128,		// サブ画面OAM管理領域
			0, 32,		// サブ画面アフィン管理領域
			heapid);

	// セルアクター初期化
	wk->ClactSet = CLACT_U_SetEasyInit( DEMO_ACT_MAX, &wk->RendData, heapid );
}

//--------------------------------------------------------------------------------------------
/**
 * セルアクター終了
 *
 * @param	wk		ワーク
 *
 * @return	none
 */
//-------------------------------------------------------------------------------------------
static void EndCellActor( OPD_WK_PTR wk )
{
	// セルアクターセット破棄
	CLACT_DestSet(wk->ClactSet);

	//OAMレンダラー破棄
	REND_OAM_Delete();

	DeleteCharManager();
	DeletePlttManager();
}

//--------------------------------------------------------------------------------------------
/**
 * リソースマネージャ初期化
 *
 * @param	wk			ワーク
 * @param	tbl			リソーステーブルポインタ
 *
 * @return	none
 */
//-------------------------------------------------------------------------------------------
void OPD_InitResMan(OPD_WK_PTR wk, const u8 *tbl)
{
	u8 i;
	const int heapid = HEAPID_OP_DEMO;
	//リソースマネージャー初期化
	for(i=0;i<RESOURCE_NUM;i++){		//リソースマネージャー作成
		wk->ResMan[i] = CLACT_U_ResManagerInit(tbl[i], i, heapid);
	}
}

//--------------------------------------------------------------------------------------------
/**
 * リソースマネージャ解放
 *
 * @param	wk			ワーク
 *
 * @return	none
 */
//-------------------------------------------------------------------------------------------
void OPD_DelResMan(OPD_WK_PTR wk)
{
	u8 i;
	for(i=0;i<RESOURCE_NUM;i++){
		CLACT_U_ResManagerDelete(wk->ResMan[i]);
	}
}

//--------------------------------------------------------------------------------------------
/**
 * リソースマネージャポインタ取得
 *
 * @param	wk
 *
 * @return	CLACT_U_RES_MANAGER_PTR	マネージャポインタ
 */
//-------------------------------------------------------------------------------------------
CLACT_U_RES_MANAGER_PTR *OPD_GetResManPtr(OPD_WK_PTR wk)
{
	return wk->ResMan;
}

//--------------------------------------------------------------------------------------------
/**
 * アクター表示開始・終了
 *
 * @param	act			アクターワークポインタ
 * @param	inFlg		表示フラグ
 *
 * @return	none
 */
//-------------------------------------------------------------------------------------------
void OPD_StartDispAct(CLACT_WORK_PTR act, const u8 inFlg)
{
	CLACT_SetAnmFlag(act,inFlg);
	CLACT_SetDrawFlag(act, inFlg);
}

//--------------------------------------------------------------------------------------------
/**
 * アクターヘッダー作成
 *
 * @param	inActID			アクターワークポインタ
 * @param	wk				ワーク
 * @param	inPriority		プライオリティ
 * @param	inVramType		VRAMタイプ
 * @param	outAdd			アクターアッドポインタ
 * @param	outClActHeader	アクターヘッダーポインタ
 *
 * @return	none
 */
//-------------------------------------------------------------------------------------------
void OPD_MakeClActHeader(const int inActID, OPD_WK_PTR wk,
						 const int inPriority,
						 const int inVramType,
						 CLACT_ADD *outAdd, CLACT_HEADER *outClActHeader)
{
	// セルアクターヘッダ作成
	CLACT_U_MakeHeader(	outClActHeader,
						inActID, inActID, inActID, inActID,
						CLACT_U_HEADER_DATA_NONE, CLACT_U_HEADER_DATA_NONE,
						0, inPriority,
						wk->ResMan[CLACT_U_CHAR_RES],
						wk->ResMan[CLACT_U_PLTT_RES],
						wk->ResMan[CLACT_U_CELL_RES],
						wk->ResMan[CLACT_U_CELLANM_RES],
						NULL,NULL);

	{
		outAdd->ClActSet	= wk->ClactSet;
		outAdd->ClActHeader	= outClActHeader;

		outAdd->mat.x		= 0;
		outAdd->mat.y		= 0;
		outAdd->mat.z		= 0;
		outAdd->sca.x		= FX32_ONE;
		outAdd->sca.y		= FX32_ONE;
		outAdd->sca.z		= FX32_ONE;
		outAdd->rot			= 0;
		outAdd->pri			= 0;
		outAdd->DrawArea	= inVramType;
		outAdd->heap		= HEAPID_OP_DEMO;
	}
}

//--------------------------------------------------------------------------------------------
/**
 * 上下画面距離をセット
 *
 * @param	wk				ワーク
 * @param	inMX	メイン画面X
 * @param	inMY	メイン画面Y
 * @param	inSX	サブ画面X
 * @param	inSY	サブ画面Y
 *
 * @return	none
 */
//-------------------------------------------------------------------------------------------
void OPD_SetDispDistance( OPD_WK_PTR wk,
						  const int inMX, const int inMY,
						  const int inSX, const int inSY )
{
	CLACT_U_SetSubSurfaceMatrix( &wk->RendData, inSX*FX32_ONE, inSY*FX32_ONE );
	CLACT_U_SetMainSurfaceMatrix( &wk->RendData, inMX*FX32_ONE, inMY*FX32_ONE );
}

//--------------------------------------------------------------------------------------------
/**
 * アルファブレンドセット
 *
 * @param	alpha_wk			ワーク
 * @param	inMaskA				マスクA
 * @param	inMaskB				マスクB
 * @param	inBldFrm			ブレンドにかけるフレーム
 * @param	inFadeType			フェードタイプインかアウトか
 * @param	inIsMain			対象面はメイン画面か？
 *
 * @return	none
 */
//-------------------------------------------------------------------------------------------
void OPD_SetAlphaBlend( BLEND_WORK * alpha_wk, const int inMaskA, const int inMaskB,
		const int inBldFrm, const int inFadeType, const BOOL inIsMain )
{
	alpha_wk->Counter = 0;
	alpha_wk->Alpha = 0;
	alpha_wk->End = 0;

	alpha_wk->IsMain = inIsMain;
	alpha_wk->MaskA = inMaskA;
	alpha_wk->MaskB = inMaskB;
	alpha_wk->BlendFrm = inBldFrm;
	alpha_wk->FadeType = inFadeType;

	alpha_wk->Tcb = TCB_Add( TCB_BlendIn, alpha_wk, 0 );
}

//--------------------------------------------------------------------------------------------
/**
 * ブレンドインTBC
 *
 * @param	tcb				TCBポインタ
 * @param	work			ワークポインタ
 *
 * @return	none
 */
//-------------------------------------------------------------------------------------------
static void TCB_BlendIn( TCB_PTR tcb, void* work )
{
	BLEND_WORK *wk = work;
	int alpha;
	wk->Counter++;

	wk->Alpha = (31 * wk->Counter) / wk->BlendFrm;

//	OS_Printf("alpha=%d\n", wk->Alpha);

	if (wk->Alpha >= 31){
		wk->Alpha = 31;
		TCB_Delete(wk->Tcb);
		wk->Tcb = NULL;
		wk->End = 1;
	}

	if (wk->FadeType == FADE_TYPE_IN){
		alpha = wk->Alpha;
	}else{
		alpha = 31 - wk->Alpha;
	}
	if (wk->IsMain){
		G2_SetBlendAlpha( wk->MaskA, wk->MaskB, alpha, 31-alpha);
	}else{
		G2S_SetBlendAlpha( wk->MaskA, wk->MaskB, alpha, 31 - alpha);
	}
}

//--------------------------------------------------------------------------------------------
/**
 * スクロールリクエスト　Vタスク版
 *
 * @param	ini				BGL
 * @param	mng				スクロールマネージャポインタ
 * @param	inTarget		対象BG
 * @param	inXOfs			Xオフセット
 * @param	inYOfs			Yオフセット
 * @param	inFrm			スクロールフレーム数
 *
 * @return	none
 */
//-------------------------------------------------------------------------------------------
void OPD_ReqScroll(	GF_BGL_INI * ini, SCROLL_MANG *mng, const int inTarget,
						const s16 inXOfs, const s16 inYOfs,	const int inFrm )
{
	u8 idx;
	u8 is_main;
	SCROLL_WORK *wk;

	is_main = 0;

	idx = GetFrmIdx(inTarget);
	if (idx < 4){
		is_main = 1;
	}

	wk = &mng->Work[idx];
	if (wk->Valid){
		OS_Printf("稼働中\n");
		GF_ASSERT(0);
		return;
	}

	if (inFrm == 0){		//即スクロール終了
		int x,y;
		x = GF_BGL_ScrollGetX( ini, inTarget )+inXOfs;
		y = GF_BGL_ScrollGetY( ini, inTarget )+inYOfs;
		GF_BGL_ScrollSet( ini, inTarget, GF_BGL_SCROLL_X_SET, x );
		GF_BGL_ScrollSet( ini, inTarget, GF_BGL_SCROLL_Y_SET, y );
		return;
	}

	wk->Bgl = ini;
	wk->BgFrame = inTarget;
	wk->Counter = 0;
	wk->End = 0;
	wk->Frm = inFrm;
	wk->OrgX = GF_BGL_ScrollGetX( ini, inTarget );
	wk->OrgY = GF_BGL_ScrollGetY( ini, inTarget );
	wk->OfsX = inXOfs;
	wk->OfsY = inYOfs;
	wk->Valid = TRUE;

	wk->Tcb = VIntrTCB_Add( TCB_Scroll, wk, 0 );

}

//--------------------------------------------------------------------------------------------
/**
 * スクロールリクエスト　通常タスク版
 *
 * @param	ini				BGL
 * @param	mng				スクロールマネージャポインタ
 * @param	inTarget		対象BG
 * @param	inXOfs			Xオフセット
 * @param	inYOfs			Yオフセット
 * @param	inFrm			スクロールフレーム数
 *
 * @return	none
 */
//-------------------------------------------------------------------------------------------
void OPD_ReqScrollNorm(	GF_BGL_INI * ini, SCROLL_MANG *mng, const int inTarget,
						const s16 inXOfs, const s16 inYOfs,	const int inFrm )
{
	u8 idx;
	u8 is_main;
	SCROLL_WORK *wk;

	is_main = 0;

	idx = GetFrmIdx(inTarget);
	if (idx < 4){
		is_main = 1;
	}

	wk = &mng->Work[idx];
	if (wk->Valid){
		OS_Printf("稼働中\n");
		GF_ASSERT(0);
		return;
	}

	if (inFrm == 0){		//即スクロール終了
		int x,y;
		x = GF_BGL_ScrollGetX( ini, inTarget )+inXOfs;
		y = GF_BGL_ScrollGetY( ini, inTarget )+inYOfs;
		GF_BGL_ScrollSet( ini, inTarget, GF_BGL_SCROLL_X_SET, x );
		GF_BGL_ScrollSet( ini, inTarget, GF_BGL_SCROLL_Y_SET, y );
		return;
	}

	wk->Bgl = ini;
	wk->BgFrame = inTarget;
	wk->Counter = 0;
	wk->End = 0;
	wk->Frm = inFrm;
	wk->OrgX = GF_BGL_ScrollGetX( ini, inTarget );
	wk->OrgY = GF_BGL_ScrollGetY( ini, inTarget );
	wk->OfsX = inXOfs;
	wk->OfsY = inYOfs;
	wk->Valid = TRUE;

	wk->Tcb = TCB_Add( TCB_ScrollNorm, wk, 0 );

}

//--------------------------------------------------------------------------------------------
/**
 * スクロールＴＣＢ	Vタスク
 *
 * @param	tcb				TCBポインタ
 * @param	work			ワークポインタ
 *
 * @return	none
 */
//-------------------------------------------------------------------------------------------
static void TCB_Scroll( TCB_PTR tcb, void* work )
{
	int x,y;
	SCROLL_WORK *wk = work;

	//フレームマイナス指定は無限ループ
	if (wk->Frm < 0){
		x = GF_BGL_ScrollGetX( wk->Bgl, wk->BgFrame ) + wk->OfsX;
		y = GF_BGL_ScrollGetY( wk->Bgl, wk->BgFrame ) + wk->OfsY;
	}else{
		wk->Counter++;
		x = (wk->OfsX * wk->Counter) / wk->Frm;
		y = (wk->OfsY * wk->Counter) / wk->Frm;
		x += wk->OrgX;
		y += wk->OrgY;

		if (wk->Counter >= wk->Frm){
			TCB_Delete(wk->Tcb);
			wk->Tcb = NULL;
			wk->End = 1;
			wk->Valid = FALSE;
		}
	}

	GF_BGL_ScrollSet( wk->Bgl, wk->BgFrame, GF_BGL_SCROLL_X_SET, x );
	GF_BGL_ScrollSet( wk->Bgl, wk->BgFrame, GF_BGL_SCROLL_Y_SET, y );
}

//--------------------------------------------------------------------------------------------
/**
 * スクロールＴＣＢ　通常タスク
 *
 * @param	tcb				TCBポインタ
 * @param	work			ワークポインタ
 *
 * @return	none
 */
//-------------------------------------------------------------------------------------------
static void TCB_ScrollNorm( TCB_PTR tcb, void* work )
{
	int x,y;
	SCROLL_WORK *wk = work;

	//フレームマイナス指定は無限ループ
	if (wk->Frm < 0){
		x = GF_BGL_ScrollGetX( wk->Bgl, wk->BgFrame ) + wk->OfsX;
		y = GF_BGL_ScrollGetY( wk->Bgl, wk->BgFrame ) + wk->OfsY;
	}else{
		wk->Counter++;
		x = (wk->OfsX * wk->Counter) / wk->Frm;
		y = (wk->OfsY * wk->Counter) / wk->Frm;
		x += wk->OrgX;
		y += wk->OrgY;

		if (wk->Counter >= wk->Frm){
			TCB_Delete(wk->Tcb);
			wk->Tcb = NULL;
			wk->End = 1;
			wk->Valid = FALSE;
		}
	}

	GF_BGL_ScrollReq( wk->Bgl, wk->BgFrame, GF_BGL_SCROLL_X_SET, x );
	GF_BGL_ScrollReq( wk->Bgl, wk->BgFrame, GF_BGL_SCROLL_Y_SET, y );
}

//--------------------------------------------------------------------------------------------
/**
 * スクロール終了チェック
 *
 * @param	mng			スクロールマネージャポインタ
 * @param	inTarget	スクロール対象BG
 *
 * @return	BOOL		TRUEでスクロール終了
 */
//-------------------------------------------------------------------------------------------
BOOL OPD_CheckScrollEnd(SCROLL_MANG *mng, const int inTarget)
{
	BOOL rc = FALSE;
	u8 idx = GetFrmIdx(inTarget);
	SCROLL_WORK *wk = &(mng->Work[idx]);

	if (!wk->Valid){
		return TRUE;
	}

	if (wk->End){
		rc = TRUE;
	}

	return rc;
}

//--------------------------------------------------------------------------------------------
/**
 * スクロールＴＣＢの停止
 *
 * @param	mng			スクロールマネージャポインタ
 * @param	inTarget	スクロール対象BG
 *
 * @return	none
 */
//-------------------------------------------------------------------------------------------
void OPD_StopScrollTcb(SCROLL_MANG *mng, const int inTarget)
{
	u8 idx = GetFrmIdx(inTarget);
	SCROLL_WORK *wk = &(mng->Work[idx]);
	if (wk->Valid){
		TCB_Delete(wk->Tcb);
		wk->Tcb = NULL;
		wk->End = 1;
		wk->Valid = FALSE;
	}
}

//--------------------------------------------------------------------------------------------
/**
 * BGフレームのインデックス取得
 *
 * @param	inBgFrame
 *
 * @return	u8			インデックス
 */
//-------------------------------------------------------------------------------------------
static u8 GetFrmIdx(const int inBgFrame)
{
	u8 idx = 0;
	switch(inBgFrame){
	case GF_BGL_FRAME0_M:
		idx = 0;
		break;
	case GF_BGL_FRAME1_M:
		idx = 1;
		break;
	case GF_BGL_FRAME2_M:
		idx = 2;
		break;
	case GF_BGL_FRAME3_M:
		idx = 3;
		break;
	case GF_BGL_FRAME0_S:
		idx = 4;
		break;
	case GF_BGL_FRAME1_S:
		idx = 5;
		break;
	case GF_BGL_FRAME2_S:
		idx = 6;
		break;
	case GF_BGL_FRAME3_S:
		idx = 7;
		break;
	default:
		GF_ASSERT(0);
	}

	return idx;
}

//--------------------------------------------------------------------------------------------
/**
 * ウィンドウコントロール
 *
 * @param	cnt_wk		コントローラ
 * @param	inFrm		かかるフレーム数
 * @param	inIsMain	対象がメイン画面か？
 * @param	inParam		ウィンドウパラメータ
 *
 * @return	WND_WORK		ウィンドウワークポインタ
 */
//-------------------------------------------------------------------------------------------
WND_WORK * OPD_ReqWindowMove( WND_CNT_WORK *cnt_wk, const int inFrm,
								 const BOOL inIsMain, const WND_PARAM *inParam	)
{
	WND_WORK *wk;

	SetWindouw(inParam->InMask, inParam->OutMask, inParam->InEff, inParam->OutEff, inIsMain);

	//フレーム0以下のときは即反映
	if (inFrm <= 0){
		SetWinRect(inParam->DstSX, inParam->DstSY, inParam->DstEX, inParam->DstEY, inIsMain );
		return NULL;
	}
	if (inIsMain){
		wk = &cnt_wk->Work[0];
	}else{
		wk = &cnt_wk->Work[1];
	}

	wk->Param = *inParam;
	wk->Frm = inFrm;
	wk->Counter = 0;
	wk->End = 1;
	wk->Valid = TRUE;
	wk->IsMain = inIsMain;

	wk->NowSX =inParam->SrcSX;
	wk->NowSY =inParam->SrcSY;
	wk->NowEX =inParam->SrcEX;
	wk->NowEY =inParam->SrcEY;

	SetWinRect(inParam->SrcSX, inParam->SrcSY, inParam->SrcEX, inParam->SrcEY, inIsMain );


	wk->Tcb = VIntrTCB_Add( TCB_Wnd, wk, 0 );

	return wk;
}

//--------------------------------------------------------------------------------------------
/**
 * ウィンドウ動作終了チェック
 *
 * @param	cnt_wk		コントローラ
 * @param	inIsMain	対象がメイン画面か？
 *
 * @return	BOOL		TRUEで終了
 */
//-------------------------------------------------------------------------------------------
BOOL OPD_CheckWndEnd(WND_CNT_WORK *cnt_wk, const BOOL inIsMain)
{
	WND_WORK *wk;
	if (inIsMain){
		wk = &cnt_wk->Work[0];
	}else{
		wk = &cnt_wk->Work[1];
	}
	if (wk->Valid == FALSE){
		return TRUE;
	}
	if (wk->End){
		return TRUE;
	}

	return FALSE;

}

//--------------------------------------------------------------------------------------------
/**
 * ウィンドウコントロールTCB
 *
 * @param	tcb			TCBポインタ
 * @param	work		ワークポインタ
 *
 * @return	none
 */
//-------------------------------------------------------------------------------------------
static void TCB_Wnd( TCB_PTR tcb, void* work )
{
	int sx,sy,ex,ey;
	int dif;
	WND_WORK *wk = work;

	wk->Counter++;

	dif = wk->Param.DstSX - wk->Param.SrcSX;
	sx = wk->Param.SrcSX + (dif*wk->Counter) / wk->Frm;
	dif = wk->Param.DstSY - wk->Param.SrcSY;
	sy = wk->Param.SrcSY + (dif*wk->Counter) / wk->Frm;
	dif = wk->Param.DstEX - wk->Param.SrcEX;
	ex = wk->Param.SrcEX + (dif*wk->Counter) / wk->Frm;
	dif = wk->Param.DstEY - wk->Param.SrcEY;
	ey = wk->Param.SrcEY + (dif*wk->Counter) / wk->Frm;

	wk->NowSX =sx;
	wk->NowSY =sy;
	wk->NowEX =ex;
	wk->NowEY =ey;

	if (wk->Counter >= wk->Frm){
		TCB_Delete(wk->Tcb);
		wk->Tcb = NULL;
		wk->End = 1;
		wk->Valid = FALSE;
	}

	SetWinRect(sx, sy, ex, ey, wk->IsMain );
}

//--------------------------------------------------------------------------------------------
/**
 * ウィンドウ設定
 *
 * @param	inInside		ウィンドウ内部マスク
 * @param	inOutside		ウィンドウ外部マスク
 * @param	inInEff			ウィンドウ内部カラー特殊効果有無
 * @param	inOutEff		ウィンドウ外部カラー特殊効果有無
 * @param	inIsMain		対象面はメインか？
 *
 * @return	none
 */
//-------------------------------------------------------------------------------------------
static void SetWindouw(	const int inInside, const inOutside,
						const u8 inInEff, const u8 inOutEff, const BOOL inIsMain)
{
	if (inIsMain){
		GX_SetVisibleWnd( GX_WNDMASK_W0|GX_WNDMASK_W1 );
		G2_SetWnd0InsidePlane( inInside, inInEff );
		G2_SetWnd1InsidePlane( inInside, inInEff );
		G2_SetWndOutsidePlane( inOutside, inInEff );
	}else{
		GXS_SetVisibleWnd( GX_WNDMASK_W0|GX_WNDMASK_W1 );
		G2S_SetWnd0InsidePlane( inInside, inOutEff );
		G2S_SetWnd1InsidePlane( inInside, inOutEff );
		G2S_SetWndOutsidePlane( inOutside, inOutEff );
	}
}

//--------------------------------------------------------------------------------------------
/**
 * ウィンドウ矩形設定
 *
 * @param	inSX		ウィンドウ開始X
 * @param	inSY		ウィンドウ開始Y
 * @param	inEX		ウィンドウ終了X
 * @param	inEY		ウィンドウ終了Y
 * @param	inIsMain	対象面はメインか？
 *
 * @return	none
 */
//-------------------------------------------------------------------------------------------
static void SetWinRect(const int inSX, const int inSY, const int inEX, const int inEY, const BOOL inIsMain )
{
	if ((inSX == 0)&&(inEX == 255)){
		int wnd1_sx = 0;
		int wnd1_ex = 1;
		int wnd0_sx = 1;
		int wnd0_ex = 0;
		if (inIsMain){
			G2_SetWnd1Position( wnd1_sx, inSY, wnd1_ex, inEY );
			G2_SetWnd0Position( wnd0_sx, inSY, wnd0_ex, inEY );
		}else{
			G2S_SetWnd1Position( wnd1_sx, inSY, wnd1_ex, inEY );
			G2S_SetWnd0Position( wnd0_sx, inSY, wnd0_ex, inEY );
		}
	}else{
		if (inIsMain){
			G2_SetWnd0Position( inSX, inSY, inEX, inEY );
		}else{
			G2S_SetWnd0Position( inSX, inSY, inEX, inEY );
		}
	}
}

////////////////////////////////////////
//アクセス関数

//--------------------------------------------------------------------------------------------
/**
 * BGL取得
 *
 * @param	ptr		ワーク
 *
 * @return	none
 */
//--------------------------------------------------------------------------------------------
GF_BGL_INI *OPD_GetBGL(OPD_WK_PTR ptr)
{
	return ptr->bgl;
}

//--------------------------------------------------------------------------------------------
/**
 * 画面エフェクトワークアドレス取得
 *
 * @param	ptr		ワーク
 *
 * @return	none
 */
//--------------------------------------------------------------------------------------------
DISP_EFF_WORK *GetDispEffWorkAdr(OPD_WK_PTR ptr)
{
	return &ptr->Dew;
}

//--------------------------------------------------------------------------------------------
/**
 * スキップフラグ取得
 *
 * @param	ptr		ワーク
 *
 * @return	none
 */
//--------------------------------------------------------------------------------------------
const BOOL OPD_GetSkipFlg(OPD_WK_PTR ptr)
{
	return ptr->SkipFlg;
}

//--------------------------------------------------------------------------------------------
/**
 * フレームカウンタ取得
 *
 * @param	ptr		ワーク
 *
 * @return	none
 */
//--------------------------------------------------------------------------------------------
const int OPD_GetFrmCounter(OPD_WK_PTR ptr)
{
	return ptr->FrameCounter;
}

//--------------------------------------------------------------------------------------------
/**
 * レジスタ使用画面エフェクトクリア
 *
 * @param	ptr		ワーク
 *
 * @return	none
 */
//--------------------------------------------------------------------------------------------
void OPD_ResetDispEff(OPD_WK_PTR ptr)
{
	int i;
	//ブレンド初期化
	G2_BlendNone();
	G2S_BlendNone();
	//ウィンドウ初期化
	GX_SetVisibleWnd(GX_WNDMASK_NONE);
	GXS_SetVisibleWnd(GX_WNDMASK_NONE);
	//スクロールオフセット初期化
	for (i=0;i<8;i++){
		GF_BGL_ScrollSet( ptr->bgl, i, GF_BGL_SCROLL_X_SET, 0 );
		GF_BGL_ScrollSet( ptr->bgl, i, GF_BGL_SCROLL_Y_SET, 0 );
	}
}

//--------------------------------------------------------------------------------------------
/**
 * オリジナルワイプ開始
 *
 * @param	ptr			ワーク
 * @param	inWipeType	ワイプタイプ
 * @param	inIsMain	対象はメインか？
 * @param	inFrm		かけるフレーム数
 *
 * @return	none
 */
//--------------------------------------------------------------------------------------------
void OPD_WipeStart(	OPD_WK_PTR ptr, const u8 inWipeType, const BOOL inIsMain, const int inFrm)
{
	WIPE_WORK *wk;
	int inside;
	int outside;
	int frame;
	int color;
	int disp;
	u8 wipe_in = 0;

	inside = GX_WND_PLANEMASK_BG0|GX_WND_PLANEMASK_BG1|GX_WND_PLANEMASK_BG2|
			GX_WND_PLANEMASK_BG3|GX_WND_PLANEMASK_OBJ;
	outside = GX_WND_PLANEMASK_NONE;

	wk = &ptr->Dew.WipeWork;
	wk->Valid = TRUE;
	wk->End = 0;
	wk->Frm = inFrm;
	wk->Counter = 0;
	wk->IsMain = inIsMain;
	wk->FX = FX32_ONE;
	wk->FY = 0;
	wk->Type = inWipeType;

	if (inIsMain){
		frame = GF_BGL_FRAME0_M;
		disp = WIPE_DISP_MAIN;
	}else{
		frame = GF_BGL_FRAME0_S;
		disp = WIPE_DISP_SUB;
	}

	if ( (wk->Type == WIPE_WHITE_IN)||(wk->Type == WIPE_WHITE_OUT) ){
		color = 0x7fff;
	}else{
		color = 0;
	}
	GF_BGL_BackGroundColorSet( frame, color );

	if ( (wk->Type == WIPE_WHITE_IN)||(wk->Type == WIPE_BLACK_IN) ){
		int tmp = inside;
		inside = outside;
		outside = tmp;
		wipe_in = 1;
	}
	//ウィンドウマスク
	SetWinRect(0, 0, 255, 192, inIsMain );
	SetWindouw(	inside, outside, 1, 1, inIsMain);

	//ワイプインのときはウィンドウ設定の後、輝度を戻す
	if (wipe_in){
		WIPE_ResetBrightness( disp );
	}

	wk->Tcb = TCB_Add(TCB_Wipe, wk, 0);
	sys_HBlankIntrSet( WipeHBlank, wk );		// HBlankセット
}

//--------------------------------------------------------------------------------------------
/**
 * オリジナルワイプ終了チェック
 *
 * @param	ptr			ワーク
 *
 * @return	BOOL		TRUEで終了
 */
//--------------------------------------------------------------------------------------------
BOOL OPD_CheckWipeEnd( OPD_WK_PTR ptr )
{
	WIPE_WORK *wk = &ptr->Dew.WipeWork;

	if (!wk->Valid){
		return TRUE;
	}
	if (wk->End){
		return TRUE;
	}
	return FALSE;
}

//--------------------------------------------------------------------------------------------
/**
 * オリジナルワイプTCB
 *
 * @param	tcb		TCBポインタ
 * @param	work	ワークポインタ
 *
 * @return	none
 */
//--------------------------------------------------------------------------------------------
static void TCB_Wipe( TCB_PTR tcb, void* work )
{
	int x,y;
	WIPE_WORK *wk = work;

	u16 rad;

	rad = (WIPE_RAD * wk->Counter) / wk->Frm;

	wk->FX = FX_CosIdx(rad);
	wk->FY = FX_SinIdx(rad);

	wk->Counter++;
	if (wk->Counter >= wk->Frm){
		u8 disp;
		TCB_Delete(wk->Tcb);
		wk->Tcb = NULL;
		wk->End = 1;
		wk->Valid = FALSE;

		if (wk->IsMain){
			disp = WIPE_DISP_MAIN;
		}else{
			disp = WIPE_DISP_SUB;
		}

		if (wk->Type == WIPE_WHITE_OUT){
			//輝度変更
			WIPE_SetBrightness( disp, WIPE_FADE_WHITE );
		}else if(wk->Type == WIPE_BLACK_OUT){
			WIPE_SetBrightness( disp, WIPE_FADE_BLACK );
		}else{
			//ウィンドウ効果オフ
			if (wk->IsMain){
				GX_SetVisibleWnd(GX_WNDMASK_NONE);
			}else{
				GXS_SetVisibleWnd(GX_WNDMASK_NONE);
			}
			//輝度を戻す
			WIPE_ResetBrightness( disp );
		}
		sys_HBlankIntrSet( NULL,NULL );		// HBlankセット
	}
}

//--------------------------------------------------------------------------------------------
/**
 * オリジナルワイプHブランク関数
 *
 * @param	p_work	ワークポインタ
 *
 * @return	none
 */
//--------------------------------------------------------------------------------------------
static void WipeHBlank( void* p_work )
{
	int v_count;		// Vカウント
	int add_w;
	int ex;

	WIPE_WORK *wk = (WIPE_WORK*)p_work;
	// Vカウンタを取得
	v_count = GX_GetVCount();

	if (v_count>191){
		SetWinRect(0, 0, 127, 192, wk->IsMain );
		return;
	}

	if (wk->FX == FX32_ONE){
		SetWinRect(0, 0, 255, 192, wk->IsMain );
		return;
	}else if (wk->FX == -FX32_ONE){
		SetWinRect(0, 0, 0, 192, wk->IsMain );
		return;
	}

	if (wk->FY <= 0){
		add_w = 0;
	}else{
		add_w = (v_count * wk->FX) / wk->FY;
	}

	ex = 127+add_w;
	if (ex>255){
		ex = 255;
	}else if(ex < 0){
		ex = 0;
	}

	SetWinRect(0, 0, ex, 192, wk->IsMain );
}

//--------------------------------------------------------------------------------------------
/**
 * シーンワークポインタ取得
 *
 * @param	ptr	ワークポインタ
 *
 * @return	void*		シーンワークポインタ
 */
//--------------------------------------------------------------------------------------------
static void *GetSceneWorkPtr(OPD_WK_PTR ptr)
{
	void *wk = NULL;
	switch(ptr->SceneNo){
	case 0:
		wk = &ptr->SceneWork1;
		break;
	case 1:
		wk = &ptr->SceneWork2;
		break;
	case 2:
		wk = &ptr->SceneWork3;
		break;
	case 3:
		wk = &ptr->SceneWork4;
		break;
	case 4:
		wk = &ptr->SceneWork5;
		break;
	default:
		GF_ASSERT(0);
	}
	return wk;
}

//--------------------------------------------------------------------------------------------
/**
 * シーンシーケンスシフト
 *
 * @param	work	ワークポインタ
 *
 * @return	none
 */
//--------------------------------------------------------------------------------------------
void OPD_IncSceneSeq(OPD_WK_PTR ptr)
{
	ptr->SceneSeq++;
	ptr->SceneCounter = 0;
}

//--------------------------------------------------------------------------------------------
/**
 * シーンシーケンス取得
 *
 * @param	ptr	ワークポインタ
 *
 * @return	u8		シーンシーケンス
 */
//--------------------------------------------------------------------------------------------
u8 OPD_GetSceneSeq(OPD_WK_PTR ptr)
{
	return ptr->SceneSeq;
}

//--------------------------------------------------------------------------------------------
/**
 * シーンカウンター取得
 *
 * @param	ptr	ワークポインタ
 *
 * @return	u8	シーンカウンタ
 */
//--------------------------------------------------------------------------------------------
u8 OPD_GetSceneCount(OPD_WK_PTR ptr)
{
	return ptr->SceneCounter;
}